package com.audaque.springboot.foshanupload.redis.aspect;

/**
 * @author zgb
 * @desc ...
 * @date 2021-12-26 19:25:58
 */


import com.audaque.springboot.foshanupload.redis.anno.RedisLuaIncrRateLimiterAnno;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
@Slf4j
@Aspect
@Component
public class RedisLuaIncrRateLimiterAnnoAspect {

    /**
     * 注入redis操作类
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private DefaultRedisScript<List> redisScript;

    /**
     * 初始化 redisScript 类
     * 返回值为 List
     */
    @PostConstruct
    public void init(){
        redisScript = new DefaultRedisScript<List>();
        redisScript.setResultType(List.class);
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("luascript/redisLuaIncrRateLimiterAnno.lua")));
    }



    @Pointcut("@annotation(com.audaque.springboot.foshanupload.redis.anno.RedisLuaIncrRateLimiterAnno)")
    public void pointcutName() {
    }

    @Around("pointcutName()")
    public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature  signature = (MethodSignature)proceedingJoinPoint.getSignature();
        //使用Java 反射技术获取方法上是否有@RedisRateLimiter 注解类
        RedisLuaIncrRateLimiterAnno redisRateLimiter = signature.getMethod().getDeclaredAnnotation(RedisLuaIncrRateLimiterAnno.class);
        if(redisRateLimiter == null){
            //正常执行方法,执行正常业务逻辑
            return proceedingJoinPoint.proceed();
        }
        //获取注解上的参数，获取配置的速率
        double value = redisRateLimiter.value();
        String name = redisRateLimiter.name();
        String msg = redisRateLimiter.msg();
        Boolean resultYn = redisRateLimiter.resultYn();

        //list设置lua的keys[1]
        List<String> keyList = Lists.newArrayList(name);

        //用户Mpa设置Lua 的ARGV[1]
        //List<String> argList = Lists.newArrayList(String.valueOf(value));

        String s = "0";
        if(!resultYn){
            //lua 脚本返回 "0" 表示超出流量大小，返回1表示没有超出流量大小
            while(StringUtils.equals(s,"0")){
                //调用脚本并执行
                List result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(value));
                s = result.get(0).toString();
            }
        }else{
            //lua 脚本返回 "0" 表示超出流量大小，返回1表示没有超出流量大小
            //调用脚本并执行
            List result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(value));
            s = result.get(0).toString();
            if(StringUtils.equals(s,"0")){
                throw new Exception(msg);
            }
        }
        // 没有限流，直接放行
        return proceedingJoinPoint.proceed();
    }

}
